package com.sinsz.c;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.sinsz.c.properties.DataSourceProperties;
import com.sinsz.c.properties.DruidConsoleProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 关系型数据连接设置
 *
 * @author chenjianbo
 * @date 2017年11月13日15:41:05
 */
@Configuration
@EnableConfigurationProperties(value = {
        DataSourceProperties.class,
        DruidConsoleProperties.class
})
public class BxfsMybatisDataSourceConfig {

    private final DataSourceProperties prop;

    private final DruidConsoleProperties console;

    private static final Logger logger = LoggerFactory.getLogger(BxfsMybatisDataSourceConfig.class);

    public BxfsMybatisDataSourceConfig(
            DataSourceProperties prop,
            DruidConsoleProperties console) {
        this.prop = prop;
        this.console = console;
        if (logger.isDebugEnabled()) {
            logger.debug("数据源配置已注入, 配置信息：{}, 监控配置：{}", this.prop, this.console);
        }
    }

    private static Properties connectProperties(String string) {
        Properties prop = new Properties();
        String c1 = ";",c2 = "=";
        if (string != null && string.length() > 0) {
            String[] str;
            if (string.contains(c1)) {
                str = string.split(c1);
            } else {
                str = new String[]{string};
            }
            for (String s : str) {
                if (s.contains(c2)) {
                    String[] t = s.split(c2);
                    if (t.length > 1) {
                        prop.setProperty(t[0], t[1]);
                    } else {
                        prop.setProperty(t[0], "");
                    }
                }
            }
        }
        return prop;
    }

    /**
     * 数据源
     * @return
     */
    @Primary
    @Bean(initMethod = "init", destroyMethod = "close")
    public DataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(prop.getUrl());
        datasource.setUsername(prop.getUsername());
        datasource.setPassword(prop.getPassword());
        datasource.setDriverClassName(prop.getDriverClassName());
        datasource.setInitialSize(prop.getInitialSize());
        datasource.setMinIdle(prop.getMinIdle());
        datasource.setMaxActive(prop.getMaxActive());
        datasource.setMaxWait(prop.getMaxWait());
        datasource.setTimeBetweenEvictionRunsMillis(prop.getTimeBetweenEvictionRunsMillis());
        datasource.setMinEvictableIdleTimeMillis(prop.getMinEvictableIdleTimeMillis());
        datasource.setValidationQuery(prop.getValidationQuery());
        datasource.setTestWhileIdle(prop.isTestWhileIdle());
        datasource.setTestOnBorrow(prop.isTestOnBorrow());
        datasource.setTestOnReturn(prop.isTestOnReturn());
        datasource.setPoolPreparedStatements(prop.isPoolPreparedStatements());
        datasource.setMaxPoolPreparedStatementPerConnectionSize(prop.getMaxPoolPreparedStatementPerConnectionSize());
        datasource.setUseGlobalDataSourceStat(prop.isUseGlobalDataSourceStat());
        try {
            List<Filter> list = new ArrayList<>();
            list.add(wallFilter());
            //拦截器配置
            datasource.setFilters(prop.getFilters());
            datasource.setProxyFilters(list);
        } catch (SQLException e) {
            logger.error("druid初始化数据连接异常，{}", e);
        }
        datasource.setConnectProperties(connectProperties(prop.getConnectionProperties()));
        return datasource;
    }

    /**
     * SQL注入防火墙配置
     * <p>
     *     false表示不检查；true表示需要检查
     * </p>
     * @return
     */
    @Bean
    public WallFilter wallFilter() {
        WallFilter filter = new WallFilter();
        filter.setThrowException(false);
        return filter;
    }

    /**
     * 数据源监控 - 权限设置
     * @return
     */
    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");
        reg.addInitParameter("loginUsername", console.getLoginUsername());
        reg.addInitParameter("loginPassword", console.getLoginPassword());
        reg.addInitParameter("allow",console.getAllow());
        reg.addInitParameter("deny",console.getDeny());
        reg.addInitParameter("resetEnable",String.valueOf(console.isResetEnable()));
        return reg;
    }

    /**
     * 数据源监控 - 控制台设置
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
        filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
        return filterRegistrationBean;
    }

}